package cn.genmer.test.security.utils;

/**
 * 定义线程核心数获取
 * 最常见的公式
 * Ncpu=CPU的数量
 * Ucpu=目标CPU使用率
 * W/C=等待时间与计算时间的比率
 *
 * 为保持处理器达到期望的使用率，最优的线程池的大小等于
 * Nthreads=Ncpu*Ucpu*（1+W/C）
 *
 * 基于以上
 *
 * IO密集型：一般情况下，如果存在IO，那么肯定w/c>1（阻塞耗时一般都是计算耗时的很多倍）,但是需要考虑系统内存有限（每开启一个线程都需要内存空间），
 * 这里需要上服务器测试具体多少个线程数适合（CPU占比、线程数、总耗时、内存消耗）。如果不想去测试，保守点取1即，Nthreads=Ncpu*(1+1)=2Ncpu。这样设置一般都OK。
 *
 * CPU密集型：假设没有等待w=0，则W/C=0. Nthreads=Ncpu。
 *
 * 在《Programming Concurrency on the JVM Mastering》即《Java 虚拟机并发编程》中总结为一个公式
 * 线程数 = CPU可用核心数/(1 - 阻塞系数)， 其中阻塞系数介于 0 和 1 之间。
 * @author Genmer
 *
 */
public final class ThreadPoolSizeUtil {
    
    private ThreadPoolSizeUtil() {
        
    }
    /**
     * 每个任务有 90%（大部分） 的时间会阻塞，并且只在其生命周期的 10%（小部分） 内工作。即I/O密集池
     * 这里不确定工作机器的内存情况，故保守取2倍线程数
     * @return io intesive Thread pool size
     */
    public static int ioIntesivePoolSize() {
        
        double blockingCoefficient = 0.5;
        return poolSize(blockingCoefficient);
    }

    /**
     * 每个任务有 90%（大部分） 的时间会阻塞，并且只在其生命周期的 10%（小部分） 内工作。即I/O密集池
     * 对于 CPU 密集型的计算场景，理论上“线程的数量 =CPU 核数”就是最合适的。
     * 不过在工程上，线程的数量一般会设置为“CPU 核数 +1”，这样的话，当线程因为偶尔的内存页失效或其他原因导致阻塞时，这个额外的线程可以顶上，从而保证 CPU 的利用率
     * @return cpu intesive Thread pool size
     */
    public static int cpuIntesivePoolSize() {

        double blockingCoefficient = 0;
        return poolSize(blockingCoefficient) + 1;
    }


    /**
     * 
     * 线程数 = 可用内核数 / (1 - 阻塞 * 系数)，其中阻塞系数介于 0 和 1 之间。
     *  CPU密集型任务的阻塞系数为 0，而  IO 密集型任务具有值接近 1。
     *  @param blockingCoefficient the coefficient
     *  @return Thread pool size
     */
    public static int poolSize(double blockingCoefficient) {
        // 获取JVM可使用的逻辑核心数
        int numberOfCores = Runtime.getRuntime().availableProcessors();
        int poolSize = (int) (numberOfCores / (1 - blockingCoefficient));
        return poolSize;
    }
}